#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>

#define MAXPENDING 5

#define err_msg printf
#define sys_msg
#define debug_msg printf

char *server_config_file = "./conf/serverconf.xml";
char alx_web_dir[200];
char ServPort[5];
static int alx_conf_chk(void);
static int new_conf_create(void);

int servSock;
int clntSock;

sig_atomic_t child_exit_status;
void clean_up_child_process(int signal_number);

int HandleTCPClient(int clntSocket, char *alx_web_dir);

void killme(int sig)
{
	if(sig==-2) { printf("Alx Web Server: Bind Failed! The port is busy..\nExiting..\n"); }
	else {
		printf("Alx Web Server: Got signal to exit...\n");
		close(clntSock);
		sleep(1);
		close(servSock);
		sleep(1);
		printf("Exited..!\n");
	}
	exit(0);
}

int main()
{
	struct sockaddr_in echoServAddr;
	struct sockaddr_in echoClntAddr;
	unsigned short echoServPort;
	unsigned int clntLen;

	signal (SIGINT,  killme);
	signal (SIGTERM, killme);
	signal (SIGQUIT, killme);
	signal (SIGHUP,  SIG_IGN);
	signal (SIGCHLD,  SIG_IGN);
	signal (SIGCLD,  SIG_IGN);

	alx_conf_chk();

	echoServPort = atoi(ServPort);

	if ((servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) sys_msg("socket()");

	memset(&echoServAddr, 0, sizeof(echoServAddr));
	echoServAddr.sin_family = AF_INET;
	echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY);
	echoServAddr.sin_port = htons(echoServPort);

	struct sigaction sigchld_action;
	memset (&sigchld_action, 0, sizeof (sigchld_action));
	sigchld_action.sa_handler = &clean_up_child_process;
	sigaction (SIGCHLD, &sigchld_action, NULL);

	if (bind(servSock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0) { sys_msg("bind()"); killme(-2); }

	if (listen(servSock, MAXPENDING) < 0) perror("listen()");

	debug_msg("Server started on port: %d\n", echoServPort);
        debug_msg("Hosted contents from:   %s\n", alx_web_dir);

	daemon(1, 0);

	for (;;)
	{
		clntLen = sizeof(echoClntAddr);
		if ((clntSock = accept(servSock, (struct sockaddr *) &echoClntAddr, &clntLen)) < 0) sys_msg("accept()");
		// debug_msg("Handling client %s\n", inet_ntoa(echoClntAddr.sin_addr));
		HandleTCPClient(clntSock, alx_web_dir);
		close(clntSock);
	}
}

void clean_up_child_process(int signal_number)
{
        int status;
        wait (&status);
        debug_msg("Removing_process:>> %d\n", status);
        child_exit_status = status;
}

static int alx_conf_chk(void)
{
        FILE *fp; int i=0, j=0, found=0; char TAGGS[2], DataLine[50];
        if(!(fp = fopen(server_config_file, "r")))
        {
                debug_msg("Server config file not found! Creating new..\n");
                if(new_conf_create())
                {
                        err_msg("Error creating %s\n", server_config_file); exit(1);
                }
                else if(!(fp = fopen(server_config_file, "r")))
                {
                        err_msg("Error creating %s\n", server_config_file); exit(2);
                }
        }
                                                                                                                                             
        while(!feof(fp))
        {
                fgets(TAGGS, 2, fp);
		DataLine[i]=*TAGGS;
		i++;

		switch(found)
		{
			case  1: alx_web_dir[j]=*TAGGS; j++;		break;
			case -1: alx_web_dir[j-1]='\0'; j=0; found=0;	break;
			case  2: ServPort[j]=*TAGGS;    j++;		break;
			case -2: ServPort[j-1]='\0';    j=0; found=0;	break;
		}
                if( *TAGGS == '>')
                {
                        DataLine[i-1]='\0'; i=0;
                        if(strcmp(DataLine, "home_dir")==0) found=1;
			else if(strcmp(DataLine, "server_port")==0) found=2;
                        else found=0;
                }
                if( *TAGGS == '<') { i=0; found=found*-1; }
        }
        fclose(fp);
        if(alx_web_dir[strlen(alx_web_dir)-1]=='/') alx_web_dir[strlen(alx_web_dir)-1]='\0';
}

static int new_conf_create(void)
{
        FILE *fd;
        int f;
                                                                                                                                             
        if((f = open(server_config_file, O_CREAT | O_RDWR | O_EXCL, 0660)) < 0)  return(-1);
                                                                                                                                             
        fd = fdopen(f, "w");
                                                                                                                                             
        fprintf(fd, "<!-- Alx webserver configuration -->\n\n");
        fprintf(fd, "<alx_serverconf>\n");
	fprintf(fd, "\t<server_port>80</server_port>\n");
        fprintf(fd, "\t<home_dir>webdir</home_dir>\n");
        fprintf(fd, "</alx_serverconf>\n");
                                                                                                                                             
        fclose(fd);
        close(f);
        return(0);
}
